#include "RpcClient.h"


//protected
RpcClient::RpcClient() :
    m_hBinding(NULL),
    m_pchBindingString(NULL),
    m_strSvcAddress(""),
    m_strSvcEndpoint(""),
    m_errCode(NO_ERROR),
    m_errInfo(""),
    m_fIsConnected(false)
{ }

//protected
RpcClient::RpcClient(__in std::string &svcAddress, __in std::string &svcEndpoint) :
    m_hBinding(NULL),
    m_pchBindingString(NULL),
    m_strSvcAddress(svcAddress),
    m_strSvcEndpoint(svcEndpoint),
    m_errCode(NO_ERROR),
    m_errInfo(""),
    m_fIsConnected(false)
{}

//protected
RpcClient::~RpcClient() {

    _Unbind();

    m_hBinding = NULL;
    m_pchBindingString = NULL;
    m_strSvcAddress.clear();
    m_strSvcEndpoint.clear();
    m_errInfo.clear();
}

//protected
void RpcClient::_SetErrCode(__in unsigned errCode) {

    m_errCode = errCode;
}

//protected
void RpcClient::_SetErrInfo(__in const char  *errInfo) {

    m_errInfo = errInfo;
}

// protected 
void RpcClient::_AddErrInfo(__in const char *errInfo) {

    m_errInfo.append(errInfo);
}

//private
bool RpcClient::_IdleCleanup() {

    RPC_STATUS status = S_OK;


    if (InqIsBound()) {

        status = \
            RpcBindingSetOption( 
                m_hBinding, 
                RPC_C_OPT_DONT_LINGER,
                (ULONG_PTR)TRUE
                );

        if (status != S_OK) {
        
            _SetErrCode(status);

            _SetErrInfo(__FUNCTION__ ": RpcBindingSetOption(RPC_C_OPT_DONT_LINGER) failed.");

            return false;
        }
    }

    status = RpcMgmtEnableIdleCleanup();

    if (status != S_OK) {

        _SetErrCode(status);

        _SetErrInfo(__FUNCTION__ ": RpcMgmtEnableIdleCleanup() failed.");
    }

    return (status == S_OK);
}

//protected
bool RpcClient::_Bind() {

    RPC_STATUS status = S_OK;


    if (InqIsBound()) {

        return true;
    }

    if (NULL != m_pchBindingString) {

        RpcStringFreeA( &m_pchBindingString);

        m_pchBindingString = NULL;
    }

    status = \
        RpcStringBindingComposeA(
            NULL,
            reinterpret_cast<PUCHAR>("ncacn_ip_tcp"),
            reinterpret_cast<PUCHAR>((char*)m_strSvcAddress.c_str()),
            reinterpret_cast<PUCHAR>((char*)m_strSvcEndpoint.c_str()),
            NULL,
            &m_pchBindingString
            );

    if (S_OK != status) {

        _SetErrCode(status);

        _SetErrInfo(__FUNCTION__ " : RpcStringBindingComposeA() failed.");

        return false;
    }

    status = RpcBindingFromStringBindingA( m_pchBindingString, &m_hBinding);

    if (S_OK != status) {

        _SetErrCode(status);

        _SetErrInfo(__FUNCTION__ " : RpcBindingFromStringBindingA() failed.");

        RpcStringFreeA( &m_pchBindingString );

        m_pchBindingString = NULL;
    }

    return (S_OK == status);
}

//protected
bool RpcClient::_Unbind() {

    bool bresult = false;

    // Force idle resources closing.
    bresult = _IdleCleanup();

    // Free binding handle
    if (NULL != m_hBinding) {

        RpcBindingFree( &m_hBinding );

        m_hBinding = NULL;
    }

    // Free binding string.
    if (NULL != m_pchBindingString) {

        RpcStringFreeA( &m_pchBindingString );

        m_pchBindingString = NULL;
    }
    
    return bresult;
}

//public
bool RpcClient::Configure(__in std::string &svcAddress, __in std::string &svcEndpoint) {

    if (InqIsBound()) {

        return false;
    }

    m_strSvcAddress  = svcAddress;

    m_strSvcEndpoint = svcEndpoint;

    return true;
}

//public
bool RpcClient::InqIsConnected() {

    return m_fIsConnected;
}

//public
bool RpcClient::InqIsBound() {

    return (NULL != m_hBinding);
}

//protected
bool RpcClient::_SetIsConnected(__in bool fIsConnected) {

    return (m_fIsConnected = fIsConnected);
}
